home *** CD-ROM | disk | FTP | other *** search
- (herald (back_end reg)
- (env t (orbit_top defs) (back_end closure) (back_end bookkeep)))
-
- ;;; Copyright (c) 1985 Yale University
- ;;; Authors: N Adams, R Kelsey, D Kranz, J Philbin, J Rees.
- ;;; This material was developed by the T Project at the Yale University Computer
- ;;; Science Department. Permission to copy this software, to redistribute it,
- ;;; and to use it for any purpose is granted, subject to the following restric-
- ;;; tions and understandings.
- ;;; 1. Any copy made of this software must include this copyright notice in full.
- ;;; 2. Users of this software agree to make their best efforts (a) to return
- ;;; to the T Project at Yale any improvements or extensions that they make,
- ;;; so that these may be included in future releases; and (b) to inform
- ;;; the T Project of noteworthy uses of this software.
- ;;; 3. All materials developed as a consequence of the use of this software
- ;;; shall duly acknowledge such use, in accordance with the usual standards
- ;;; of acknowledging credit in academic research.
- ;;; 4. Yale has made no warrantee or representation that the operation of
- ;;; this software will be error-free, and Yale is under no obligation to
- ;;; provide any services, by way of maintenance, update, or otherwise.
- ;;; 5. In conjunction with products arising from the use of this material,
- ;;; there shall be no use of the name of the Yale University nor of any
- ;;; adaptation thereof in any advertising, promotional, or sales literature
- ;;; without prior written consent from Yale in each case.
- ;;;
-
- ;;; Copyright (c) 1985 David Kranz
-
- (define (generate-init continuation)
- (bind ((*unit-literals* '())
- (*unit-variables* '())
- (*unit-closures* '())
- (*unit-templates* '())
- (*unit* nil)
- (*registers* (vector-fill (make-vector *virtual-registers*) nil))
- (*lambda* nil)
- (*heap-env* 0)
- (*locations* (make-table 'locations))
- (*lambda-queue* '()))
- (continuation)))
-
-
- (define (generate top-node)
- (generate-code (car (call-args (lambda-body top-node)))))
-
- (lset *assembly-comments?* nil)
- (lset *lambda-queue* '()) ;; queue of lambda bodies to process
- (lset *heap-env* nil) ;; distance of stack-pointer from "frame"
- (lset *max-temp* 0) ;; maximum number of temporaries used
- (lset *lambda* nil) ;; the procedure being compiled
- (lset *call-break?* nil)
- (lset *registers* nil)
-
- (define-local-syntax (ass-comment string . rest)
- `(if *assembly-comments?*
- (emit-comment (format nil ,string ,@rest))))
-
- ;;; GENERATE-CODE Initialize lambda queue. Go.
-
- (define (generate-code node)
- (set (lambda-max-temps node) 0)
- (allocate-registers node)
- (process-lambda-queue))
-
- (define (generate-code-for-object node)
- (set *heap-env* node)
- (let ((object-proc ((call-arg 2) (lambda-body node))))
- (set *lambda* object-proc)
- (emit-template node object-proc)
- (set (lambda-max-temps object-proc) 0)
- (if (closure-env (environment-closure (lambda-env node)))
- (mark (lambda-self-var node) P))
- (maybe-allocate-red-frame object-proc)
- (if (n-ary? object-proc)
- (n-ary-setup object-proc))
- (mark-vars-in-regs (cdr (lambda-variables object-proc)))
- (allocate-call (lambda-body object-proc))
- (emit-tag object-proc)
- (generate-handler node object-proc))
- (process-lambda-queue))
-
-
- (define (lambda-queue node)
- (push *lambda-queue* node))
-
- (define (process-lambda-queue)
- (if *lambda-queue*
- (let ((thing (pop *lambda-queue*)))
- (xcond ((object-lambda? thing)
- (generate-code-for-object thing))
- ((lambda-node? thing)
- (generate-code thing))
- ((lap-template-struct? thing)
- (process-lap-template thing))))))
-
- ;;; ALLOCATE-REGISTERS Sets *lambda* to be the lambda-node representing the
- ;;; environment the node argument is compiled in. Generate code for the body.
-
- (define (allocate-registers node)
- (xselect (lambda-strategy node)
- ((strategy/heap)
- (set *lambda* node)
- (set *heap-env* node)
- (ass-comment "Procedure ~s (lambda ~s ...)"
- (lambda-name node)
- (append! (map variable-unique-name (lambda-variables node))
- (cond ((lambda-rest-var node) => variable-unique-name)
- (else '()))))
- (emit-template node node)
- (maybe-allocate-red-frame node))
- ((strategy/label)
- (emit-tag node)
- (set *heap-env* (variable-binder (join-point-contour (lambda-env node))))
- (cond ((fully-recursive? node)
- (set *lambda* node)
- (maybe-allocate-red-frame node))
- (else
- (set *lambda* (join-point-*lambda* (lambda-env node)))))))
- (if (n-ary? node)
- (n-ary-setup node))
- (initialize-registers node)
- (allocate-call (lambda-body node)))
-
- (define-constant (maybe-allocate-red-frame node)
- (emit maybe-pushfr node))
-
- ;;; INITIALIZE-REGISTERS Here we mark the arguments of a closure as being in
- ;;; the argument registers. For a heaped lambda there is also the environment
- ;;; in the P register. For a join point the state is initialized.
-
- (define-integrable (method-lambda node)
- (let ((p (node-parent node)))
- (if (primop-ref? (call-proc p) primop/proc+handler)
- (node-parent p)
- nil)))
-
- (define (initialize-registers node)
- (xselect (lambda-strategy node)
- ((strategy/heap)
- (cond ((method-lambda node)
- => (lambda (obj)
- (mark (lambda-self-var obj) P)
- (set *heap-env* obj)))
- (else
- (mark (lambda-self-var node) P)))
- (mark-vars-in-regs (cdr (lambda-variables node))))
- ((strategy/label)
- (ass-comment "Label procedure ~s (lambda ~s ...)"
- (lambda-name node)
- (map variable-unique-name (lambda-variables node)))
- (walk mark
- (if (continuation? node)
- (lambda-variables node)
- (cdr (lambda-variables node)))
- (join-point-arg-specs (lambda-env node)))
- (walk (lambda (pair)
- (mark (cdr pair) (car pair)))
- (join-point-global-registers (lambda-env node))))))
-
-
-
- (define (mark-vars-in-regs vars)
- (do ((vars vars (cdr vars))
- (reg A1 (fx+ reg 1)))
- ((or (fx>= reg AN) (null? vars))
- (cond (vars
- (do ((vars vars (cdr vars))
- (reg *first-stack-register* (fx+ reg 1)))
- ((null? vars)
- (modify (lambda-max-temps *lambda*)
- (lambda (temps) (max temps (fx- reg 1)))))
- (cond ((and (car vars) (variable-refs (car vars)))
- (mark (car vars) reg)
- (generate-extra-arg-move reg)))))))
- (cond ((and (car vars) (variable-refs (car vars)))
- (mark (car vars) reg)))))
-
-
- ;;; A closure is n-ary if it has a non null rest arg.
-
- (define n-ary? lambda-rest-var)
-
- (define (n-ary-setup node)
- (cond ((not (used? (lambda-rest-var node))))
- (else
- (xselect (lambda-strategy node)
- ((strategy/heap)
- (generate-nary-setup node (length (cdr (lambda-variables node)))))
- ((strategy/label)
- (mark (lambda-rest-var node) AN))))))
-
-
-
-
- (define (allocate-primop-call node)
- (let* ((prim (primop-value (call-proc node))))
- (cond ((primop.conditional? prim)
- (allocate-conditional-primop node prim))
- ((eq? prim primop/computed-goto)
- (allocate-computed-goto node prim))
- ((primop.special? prim)
- (primop.generate prim node))
- (else
- (really-allocate-primop-call node prim)))))
-
- (define (allocate-computed-goto node prim)
- (let ((reg (->register node (leaf-value (index-ref node)))))
- (emit-goto reg)
- (do ((i (call-exits node) (fx- i 1))
- (next (call-args node) (cdr next)))
- ((fx= i 0))
- (emit-branch (car next))
- (emit-noop))
- (let ((+registers+ *registers*)
- (+heap-env+ *heap-env*)
- (+lambda+ *lambda*))
- (iterate loop ((i (call-exits node)) (next (call-args node)))
- (cond ((fx= i 0))
- (else
- (set *registers* (copy-registers))
- (set *heap-env* +heap-env+)
- (set *lambda* +lambda+)
- (emit-tag (car next))
- (walk (lambda (n)
- (kill-if-dead n (car next)))
- (cdr next))
- (allocate-call (lambda-body (car next)))
- (return-registers)
- (set *registers* +registers+)
- (restore-slots)
- (loop (fx- i 1) (cdr next))))))))
-
- (define-constant (index-ref node)
- ((call-arg (fx+ (call-exits node) 1)) node))
-
-
-
- ;;; ALLOCATE-CONDITIONAL-PRIMOP When we come to a split we save the state of
- ;;; the world and traverse one arm, then restore the state and traverse the
- ;;; other.
-
- (define (allocate-conditional-primop node prim)
- (primop.generate prim node)
- (let ((then (then-cont node))
- (else (else-cont node)))
- (receive (then else) (cond ((or (leaf-node? then)
- (leaf-node? else)
- (fx< (lambda-trace then)
- (lambda-trace else)))
- (return then else))
- (t
- (return else then)))
- (let ((registers (swap *registers* (copy-registers)))
- (lam *lambda*)
- (heap-env *heap-env*))
- (emit-tag then)
- (cond ((lambda-node? then)
- (walk (lambda (n)
- (kill-if-dead n then))
- (cons else (cddr (call-args node))))
- (allocate-call (lambda-body then)))
- (t
- (allocate-conditional-continuation node then)))
- (return-registers)
- (set *lambda* lam)
- (set *heap-env* heap-env)
- (set *registers* registers))
- (restore-slots)
- (emit-tag else)
- (cond ((lambda-node? else)
- (walk (lambda (n)
- (kill-if-dead n else))
- (cons then (cddr (call-args node))))
- (allocate-call (lambda-body else)))
- (t
- (allocate-conditional-continuation node else))))))
-
- ;; We must decide whether to try to delay dereferencing the location.
- ;; We do this if the value is used just once and in the next frob and
- ;; is an operand to a primop.
-
-
- (define (really-allocate-primop-call node prim)
- (let ((c (cont node)))
- (cond ((lambda-node? c)
- (primop.generate prim node)
- (walk (lambda (node)
- (kill-if-dead node c))
- (cdr (call-args node)))
- (allocate-call (lambda-body c)))
- (else
- (primop.generate prim node)
- (walk (lambda (node)
- (if (leaf-node? node) (kill (leaf-value node))))
- (cdr (call-args node)))
- (maybe-deallocate-red-frame *lambda*)
- (clear-slots)
- (let ((j (variable-known (leaf-value c))))
- (if j
- (bug "known continuation to primop ~s" j)
- (generate-return (primop.values-returned prim))))))))
-
-
-
- (define (access/make-closure node lam)
- (let* ((closure (environment-closure (lambda-env lam))))
- (cond ((eq? closure *unit*)
- (lambda-queue lam)
- (->register node lam))
- (else
- (make-heap-closure node closure)
- AN))))
-
-
-
- (define (do-trivial-lambda node reg)
- (let ((offset (environment-cic-offset (lambda-env node))))
- (cond ((fx= offset 0)
- (generate-move AN reg))
- (else
- (generate-move-address (reg-offset AN offset) reg)))
- (cond ((reg-node reg)
- => kill))
- (lock reg)))
-
-
- ;;; MAKE-HEAP-CLOSURE The first member of the closure corresponds to the
- ;;; template so we call %make-extend with this template and the size of the
- ;;; closure to be created. Then we fill in the slots with the need variables
- ;;; and the addresses of templates for any closure-internal-closures.
-
- (define (make-heap-closure node closure)
- (if *assembly-comments?* (emit-comment "consing heap closure"))
- (let* ((members (closure-members closure))
- (template-binder (variable-binder (car members))))
- (walk (lambda (var)
- (lambda-queue (variable-binder var)))
- members)
- (free-register node AN)
- (generate-move-pcrel template-binder AN)
- (lock AN)
- (generate-extend node (closure-size closure))
- (walk (lambda (pair)
- (let ((var (car pair))
- (offset (cdr pair)))
- (cond ((eq? var *dummy-var*))
- ((memq? var members)
- (generate-move-pcrel (variable-binder var)
- (reg-offset AN (fx- offset tag/extend))))
- (else
- (generate-move (lookup-value node var)
- (reg-offset AN (fx- offset tag/extend)))))))
- (cdr (closure-env closure))))
- (unlock AN))
-
- (define exchange-hack false)
-
-